package com.ruoyi.system.service.impl;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.ApsEveryWorkDay;
import com.ruoyi.system.domain.ApsProductLine;
import com.ruoyi.system.mapper.ApsEveryWorkDayMapper;
import com.ruoyi.system.mapper.ApsProductLineMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.ApsWorkDayConfigMapper;
import com.ruoyi.system.domain.ApsWorkDayConfig;
import com.ruoyi.system.service.IApsWorkDayConfigService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工作日历设置规则Service业务层处理
 *
 * @author ruoyi
 * @date 2024-01-08
 */
@Service
public class ApsWorkDayConfigServiceImpl implements IApsWorkDayConfigService
{
    @Autowired
    private ApsWorkDayConfigMapper apsWorkDayConfigMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private ApsProductLineMapper apsProductLineMapper;

    @Autowired
    private ApsEveryWorkDayMapper apsEveryWorkDayMapper;

    /**
     * 查询工作日历设置规则
     *
     * @param id 工作日历设置规则主键
     * @return 工作日历设置规则
     */
    @Override
    public ApsWorkDayConfig selectApsWorkDayConfigById(Long id)
    {
        return apsWorkDayConfigMapper.selectApsWorkDayConfigById(id);
    }

    /**
     * 查询工作日历设置规则列表
     *
     * @param apsWorkDayConfig 工作日历设置规则
     * @return 工作日历设置规则
     */
    @Override
    public List<ApsWorkDayConfig> selectApsWorkDayConfigList(ApsWorkDayConfig apsWorkDayConfig)
    {
        // 需要查询出 顶级父类的 日历配置 和本层级的
        List<ApsWorkDayConfig> workDayConfigs = new ArrayList<>();
        if (apsWorkDayConfig.getLineId() != null || apsWorkDayConfig.getDeptId() != null) {
            // 如果不是顶级父类, 需要遍历出 它自己和顶级父类的 日历配置
            if (!"0".equals(apsWorkDayConfig.getAncestors())) {
                // 获取顶级父类的日历配置
                ApsWorkDayConfig day = new ApsWorkDayConfig();
                day.setDeptId(100L);
                List<ApsWorkDayConfig> workDays = apsWorkDayConfigMapper.selectApsWorkDayConfigList(day);
                if (StringUtils.isNotEmpty(workDays)) {
                    workDayConfigs.addAll(workDays);
                }
            }
            // 获取本部门的
            List<ApsWorkDayConfig> workDays = apsWorkDayConfigMapper.selectApsWorkDayConfigList(apsWorkDayConfig);
            if (StringUtils.isNotEmpty(workDays)) {
                workDayConfigs.addAll(workDays);
            }
        }
        return workDayConfigs;
    }

    /**
     * 新增工作日历设置规则
     *
     * @param apsWorkDayConfig 工作日历设置规则
     * @return 结果
     */
    @Override
    @Transactional
    public int insertApsWorkDayConfig(ApsWorkDayConfig apsWorkDayConfig)
    {
        apsWorkDayConfigMapper.insertApsWorkDayConfig(apsWorkDayConfig);
        // todo 需要查询出当前层级所有的日历配置, 如果是多条需要与其他配置进行优先级对比, 必须最高才可覆盖, 如果不是最高则无效,
        List<ApsWorkDayConfig> workDays = selectApsWorkDayConfigList(apsWorkDayConfig);
        ApsWorkDayConfig workDay =
                workDays.stream().sorted(Comparator.comparing(ApsWorkDayConfig::getPriority).reversed()).collect(Collectors.toList()).get(0); //优先级数字大的优先级高
                // workDays.stream().sorted(Comparator.comparing(ApsWorkDayConfig::getPriority)).collect(Collectors.toList()).get(0); //优先级数字小的优先级高
        int count = 0;
        if (Objects.equals(workDay.getDeptId(), apsWorkDayConfig.getDeptId())) {
            // 设定开始日期和结束日期
            LocalDate startDate = workDay.getStartDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            LocalDate endDate = workDay.getEndDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

            // todo 如果不是是顶级父类日历配置 只更新自己当前的
            if (workDay.getDeptId() != 100L) {
                count = setEveryWorkDay(startDate, endDate, apsWorkDayConfig);
            } else {
                // todo 如果是顶级父类, 则需要所有部门和设备全部更新
                List<SysDept> allDeptList = sysDeptMapper.selectDeptAllList(new SysDept());
                for (SysDept sysDept : allDeptList) {
                    apsWorkDayConfig.setDeptId(sysDept.getDeptId());
                    apsWorkDayConfig.setAncestors(sysDept.getAncestors());
                    count = count + setEveryWorkDay(startDate, endDate, apsWorkDayConfig);
                }
                List<ApsProductLine> apsProductLineList = apsProductLineMapper.selectApsProductLineList(new ApsProductLine());
                for (ApsProductLine apsProductLine : apsProductLineList) {
                    apsWorkDayConfig.setDeptId(apsProductLine.getDeptId());
                    apsWorkDayConfig.setLineId(apsProductLine.getId());
                    SysDept sysDept = sysDeptMapper.selectDeptListById(apsProductLine.getDeptId());
                    apsWorkDayConfig.setAncestors(sysDept.getAncestors());
                    count = count + setEveryWorkDay(startDate, endDate, apsWorkDayConfig);
                }
            }
        }
        return count;
    }

    @Transactional
    public int setEveryWorkDay(LocalDate startDate, LocalDate endDate, ApsWorkDayConfig apsWorkDayConfig) {
        int count = 0;
        // 设定工作日集合
        HashSet<DayOfWeek> workdays = new HashSet<>();
        // if (sysWorkDay.getMonday() != null) {
        workdays.add(DayOfWeek.MONDAY);
        // }
        // if (StringUtils.isNotEmpty(sysWorkDay.getTuesday())) {
        workdays.add(DayOfWeek.TUESDAY);
        // }
        // if (StringUtils.isNotEmpty(sysWorkDay.getWednesday())) {
        workdays.add(DayOfWeek.WEDNESDAY);
        // }
        // if (StringUtils.isNotEmpty(sysWorkDay.getThursday())) {
        workdays.add(DayOfWeek.THURSDAY);
        // }
        // if (StringUtils.isNotEmpty(sysWorkDay.getFriday())) {
        workdays.add(DayOfWeek.FRIDAY);
        // }
        // if (StringUtils.isNotEmpty(sysWorkDay.getSaturday())) {
        workdays.add(DayOfWeek.SATURDAY);
        // }
        // if (StringUtils.isNotEmpty(sysWorkDay.getSunday())) {
        workdays.add(DayOfWeek.SUNDAY);
        // }
        // 设定工作日历
        LocalDate currentDate = startDate;

        while (currentDate.isBefore(endDate) || currentDate.equals(endDate)) {
            if (workdays.contains(currentDate.getDayOfWeek())) {
                // 生成每一天的排班安排
                ApsEveryWorkDay sysEveryWorkDay = new ApsEveryWorkDay();
                ZoneId zoneId = ZoneId.systemDefault();
                Date date = Date.from(currentDate.atStartOfDay().atZone(zoneId).toInstant());
                sysEveryWorkDay.setDate(date);
                String dayOfWeek = null;
                switch (currentDate.getDayOfWeek()) {
                    case MONDAY:
                        dayOfWeek = "星期一";
                        break;
                    case TUESDAY:
                        dayOfWeek = "星期二";
                        break;
                    case WEDNESDAY:
                        dayOfWeek = "星期三";
                        break;
                    case THURSDAY:
                        dayOfWeek = "星期四";
                        break;
                    case FRIDAY:
                        dayOfWeek = "星期五";
                        break;
                    case SATURDAY:
                        dayOfWeek = "星期六";
                        break;
                    case SUNDAY:
                        dayOfWeek = "星期日";
                        break;
                }
                sysEveryWorkDay.setDayOfWeek(dayOfWeek);
                switch (dayOfWeek) {
                    case "星期一":
                        sysEveryWorkDay.setClassName(apsWorkDayConfig.getMonday());
                        break;
                    case "星期二":
                        sysEveryWorkDay.setClassName(apsWorkDayConfig.getTuesday());
                        break;
                    case "星期三":
                        sysEveryWorkDay.setClassName(apsWorkDayConfig.getWednesday());
                        break;
                    case "星期四":
                        sysEveryWorkDay.setClassName(apsWorkDayConfig.getThursday());
                        break;
                    case "星期五":
                        sysEveryWorkDay.setClassName(apsWorkDayConfig.getFriday());
                        break;
                    case "星期六":
                        sysEveryWorkDay.setClassName(apsWorkDayConfig.getSaturday());
                        break;
                    case "星期日":
                        sysEveryWorkDay.setClassName(apsWorkDayConfig.getSunday());
                        break;
                }
                sysEveryWorkDay.setDeptId(apsWorkDayConfig.getDeptId());
                sysEveryWorkDay.setAncestors(apsWorkDayConfig.getAncestors());
                sysEveryWorkDay.setName((new Date()).toString());
                sysEveryWorkDay.setLineId(apsWorkDayConfig.getLineId());
                int i = apsEveryWorkDayMapper.insertApsEveryWorkDay(sysEveryWorkDay);
                count = count + i;
            }
            currentDate = currentDate.plus(1, ChronoUnit.DAYS);
        }
        return count;
    }



    /**
     * 修改工作日历设置规则
     *
     * @param apsWorkDayConfig 工作日历设置规则
     * @return 结果
     */
    @Override
    @Transactional
    public int updateApsWorkDayConfig(ApsWorkDayConfig apsWorkDayConfig)
    {
        apsWorkDayConfigMapper.updateApsWorkDayConfig(apsWorkDayConfig);
        // todo 需要查询出当前层级所有的日历配置, 如果是多条需要与其他配置进行优先级对比, 必须最高才可覆盖, 如果不是最高则无效,
        List<ApsWorkDayConfig> workDays = selectApsWorkDayConfigList(apsWorkDayConfig);
        ApsWorkDayConfig workDay =
                workDays.stream().sorted(Comparator.comparing(ApsWorkDayConfig::getPriority).reversed()).collect(Collectors.toList()).get(0); //优先级数字大的优先级高
                // workDays.stream().sorted(Comparator.comparing(ApsWorkDayConfig::getPriority)).collect(Collectors.toList()).get(0); //优先级数字小的优先级高
        int count = 0;
        if (Objects.equals(workDay.getDeptId(), apsWorkDayConfig.getDeptId())) {
            // 设定开始日期和结束日期
            LocalDate startDate = workDay.getStartDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            LocalDate endDate = workDay.getEndDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

            // todo 如果不是是顶级父类日历配置 只更新自己当前的
            if (workDay.getDeptId() != 100L) {
                count = setEveryWorkDay(startDate, endDate, apsWorkDayConfig);
            } else {
                // todo 如果是顶级父类, 则需要所有部门和设备全部更新
                List<SysDept> allDeptList = sysDeptMapper.selectDeptAllList(new SysDept());
                for (SysDept sysDept : allDeptList) {
                    apsWorkDayConfig.setDeptId(sysDept.getDeptId());
                    apsWorkDayConfig.setAncestors(sysDept.getAncestors());
                    count = count + setEveryWorkDay(startDate, endDate, apsWorkDayConfig);
                }
                List<ApsProductLine> apsProductLineList = apsProductLineMapper.selectApsProductLineList(new ApsProductLine());
                for (ApsProductLine apsProductLine : apsProductLineList) {
                    apsWorkDayConfig.setDeptId(apsProductLine.getDeptId());
                    apsWorkDayConfig.setLineId(apsProductLine.getId());
                    SysDept sysDept = sysDeptMapper.selectDeptListById(apsProductLine.getDeptId());
                    apsWorkDayConfig.setAncestors(sysDept.getAncestors());
                    count = count + setEveryWorkDay(startDate, endDate, apsWorkDayConfig);
                }
            }
        }
        return count;
    }

    /**
     * 批量删除工作日历设置规则
     *
     * @param ids 需要删除的工作日历设置规则主键
     * @return 结果
     */
    @Override
    public int deleteApsWorkDayConfigByIds(Long[] ids)
    {
        return apsWorkDayConfigMapper.deleteApsWorkDayConfigByIds(ids);
    }

    /**
     * 删除工作日历设置规则信息
     *
     * @param id 工作日历设置规则主键
     * @return 结果
     */
    @Override
    public int deleteApsWorkDayConfigById(Long id)
    {
        return apsWorkDayConfigMapper.deleteApsWorkDayConfigById(id);
    }
}
